<?php
    namespace lactone\Core\Site;

    use GuzzleHttp\Client;
    use GuzzleHttp\Cookie\SetCookie;
    use GuzzleHttp\Psr7\Response;
    use GuzzleHttp\Psr7\Uri;
    use lactone\Core\Models\TaskModel;
    use lactone\Core\Object;
    use GuzzleHttp\Cookie\FileCookieJar;

    abstract class Site extends Object{

        public      $TimeOut     = 10.0;
        public      $task        = false;
        public      $request     = false;
        public      $CookieDir   = '';
        public      $QueueDriver = 'File';
        public      $QueueArgs   = [];

        public      $Tasks;

        protected   $host ;
        protected   $url    = false;
        protected   $Client = false;

        /**
         * 任务队列
         * @var
         */
        private     $Queue ;

        /**
         * 任务完成情况队列
         * @var
         */
        private     $taskCompleteQueue;

        public function __construct($Config=[]){

            parent::__construct($Config);

            \Lactone::debug($this->logMessage(\Lactone::getConfig('TaskQueue'),'site__construct'));


            $this->initClient();

            $this->initQueue();
        }

        /**
         * 初始化队列
         */
        protected function initQueue(){
            if( ($TaskQueue = \Lactone::getConfig('TaskQueue')) && (is_array($TaskQueue)) ){
                $TaskQueue['class'] = '\lactone\Core\Queue\Queue';
                $TaskQueue['ShiftLoopTime'] = 0;
                $this->Queue = \Lactone::CreateObject($TaskQueue);

            }else{
                throw new \Exception("need set taskQueue;");
            }

            if( ($taskCompleteQueue = \Lactone::getConfig('taskCompleteQueue')) && (is_array($taskCompleteQueue)) ){
                $taskCompleteQueue['class'] = '\lactone\Core\Queue\Queue';
                $taskCompleteQueue['ShiftLoopTime'] = 0;
                $this->taskCompleteQueue = \Lactone::CreateObject($taskCompleteQueue);

            }else{
                throw new \Exception("need set taskCompleteQueue;");
            }

        }

        /**
         * 初始化连接工具
         * @throws \Exception
         */
        protected function initClient(){
            $base_url = $this->getBase_url();

            $this->Client = new Client([
                'base_uri'  => $base_url,
                'timeout'   => $this->TimeOut,
            ]);
        }

        /**
         * 对数据进行初始化处理
         * @return bool
         */
        public function  init(){
            if(!$this->task) return false;

            $this->url  = new Uri($this->task['url']);

            $request = is_array($this->task['request'])?$this->task['request']:[];
            if(!isset($request['method'])) $request['method'] = 'get';
            $this->request = $request;
        }

        /**
         * 反馈的请求是否是有效的
         * @param Response $response
         */
        protected function isValid(Response $response){
            $Status =  $response->getStatusCode();
            if($Status>=200 && $Status<300){
                return true;
            }
            return false;
        }
        /**
         * 通过url的实例获取url中的http://xxx.com
         * @return string
         * @throws \Exception
         */
        protected function getBase_url(){
            if(!$url = $this->url){
                throw new \Exception("need set Url!");
            }

            if(!$scheme = $url->getScheme()){
                $scheme = 'http';
            }

            if(!$host = $url->getHost()){
                throw new \Exception("not find Host");
            }

            if(!$port = $url->getPort()){
                return $scheme.'://'.$host;
            }

            return $scheme.'://'.$host.":".$port;
        }

        /**
         * 用户是否登录，这里使用了文件做标识符
         * @return bool
         */
        public function isLogin(){
            return file_exists($this->getLoginIdentifying());
        }

        /**
         * 获取标识用户是否已经登录的文件
         * @return string
         */
        protected function getLoginIdentifying(){
            return $this->CookieDir.'/'.md5(get_called_class()).'.login';
        }

        /**
         * 创建用户已经登录的标识符
         * @return bool
         * @throws \Exception
         */
        protected function createLoginIdentifying(){
            if(!$fopen = @fopen($this->getLoginIdentifying(),'a')){
                throw new \Exception("新建文件失败!");
            }

            fclose($fopen);
            return true;
        }

        /**
         * 移除用户登录的标识符
         * @return bool
         */
        protected function removeLoginIndentifying(){
            return @unlink($this->getLoginIdentifying());
        }

        /**
         * 获取Cookie存储实例
         * @return FileCookieJar
         */
        public function getCookies(){
            static $CookieObject = false;

            if(!$CookieObject){
                $CookieObject =  new FileCookieJar($this->CookieDir.'/'.md5(get_called_class()).'.cookie');
            }

            return $CookieObject;
        }

        /**
         * 保存Cookies
         * @param Response $response
         */
        public function saveCookies(Response $response){
            $CookiesObject =  $this->getCookies();
            $Cookies       =  $response->getHeader('Set-Cookie');
            foreach($Cookies as $Cookie){
               $CookiesObject->setCookie(SetCookie::fromString($Cookie));
            }

            $CookiesObject->save($this->CookieDir.'/'.md5(get_called_class()).'.cookie');
        }


        /**
         * 当前页面是否是首页页面
         * @return bool
         */
        public function isIndexPage(){
            $path = $this->url->getPath();
            if($path == '/' || $path =='/index.php' || $path =='/index.html' || $path == '/index.htm' || empty($path)){
                return true;
            }
            return false;
        }

        /**
         * 生成下一次请求的任务任务情况
         */
        public function createRequest($method,$Referer = false,$params = []){
            if($Referer === false){
                $Referer = $this->task['url'];
            }

            return [
                'method'    => $method,
                'Referer'   => $Referer,
                'params'    => $params
            ];
        }

        /**
         * 发送post获取数据
         */
        public function send(){
            //对需要用户登录的地方进行处理
            if($this->needLogin() && !$this->isLogin()){
                 if(!$this->Login()){
                     $this->removeLoginIndentifying();
                     throw new \Exception("登录失败");
                 }else{
                    $this->createLoginIdentifying();
                 }
            }

            $path = $this->url->getPath();
            if($path == ''){
                $path = '/';
            }

            \Lactone::debug("任务(".$this->task['id'].")发送请求中!");


            //获取数据
            switch($this->request['method']){
                case 'get':
                case 'GET':
                    try{
                        $response = $this->Client->get($path,[
                            'cookies'    => $this->getCookies(),
                            'debug'      => fopen($this->CookieDir.'/debugGet.log','w')
                        ]);
                    }catch (\Exception $e){
                        $response = false;

                        $this->taskResults(TaskModel::Fail_Status);

                        \Lactone::warning($this->logMessage("任务{$this->task['id']}执行失败"));
                    }

                    break;
                case 'post':
                case 'ajaxpost':
                    $args = [
                        'cookies'    => $this->getCookies(),
                        'debug'      => fopen($this->CookieDir.'/debugPost.log','w'),
                    ];

                    $args['headers'] = [
                        'User-Agent' => 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36',
                        'Accept'     => '*/*',
                        'Accept-Encoding' =>'gzip, deflate'
                    ];

                    //post参数
                    if(!empty($this->request['params'])){
                        $args['form_params'] = $this->request['params'];
                    }

                    \Lactone::debug($this->logMessage($args,'postArgs'));
                    try{
                        $response = $this->Client->post($path,$args);
                    }catch (\Exception $e){
                        $response = false;

                        $this->taskResults(TaskModel::Fail_Status);

                        \Lactone::warning($this->logMessage("任务{$this->task['id']}执行失败"));
                    }


                    break;
            }


            //请求成功,进行数据的处理
            if(is_object($response) && $this->isValid($response)){
                $this->taskResults(TaskModel::Success_Status);

                if(!$this->process($response)){
                    return false;
                }

            }else{
                $this->taskResults(TaskModel::Fail_Status);
            }

            return false;
        }

        /**
         * 把获取到的任务发送到服务器
         * @params $tasks 任务列表
         */
        protected function sendToServer($tasks){

            return $this->_sendToServer($tasks);

            if($tasks instanceof \Generator){

                $object = $this;
                $process = new \swoole_process(function(\swoole_process $worker) use($tasks,$object){

                    $object->Queue->reset();
                    $object->taskCompleteQueue->reset();

                    $object->_sendToServer($tasks);

                }, true);

                $pid = $process->start();

                \Lactone::saveProcessPid($pid);

                \swoole_process::wait(false);
                return false;
            }

            return $this->_sendToServer($tasks);
        }

        /**
         * 把获取到的任务发送到服务器
         * @params $tasks 任务列表
         */
        protected function _sendToServer($tasks){

            if($tasks instanceof \Generator){

                $i = 0;
                while($tasks->valid()){
                    $this->pushToQueue(json_encode($tasks->current()));
                    $tasks->next();
                    if($i > 100){
                        \Lactone::info($this->logMessage("发送任务到服务器"));
                        sleep(rand(3,4));
                        $i=0;
                    }
                }

            }elseif(!empty($tasks) && is_array($tasks)){

                //把值传递给服务器，服务器重新生成任务，继续流程
                foreach($tasks as $task){
                    $this->pushToQueue(json_encode($task));
                }

            }else{
                return false;
            }

            return true;
        }

        /**
         * 添加到队列中
         */
        protected function pushToQueue($data){
            \Lactone::debug($this->logMessage($data,'pushToQueue'));
            return $this->Queue->push($data);
        }

        /**
         * 任务完成队列
         * @param $data
         * @return mixed
         */
        protected function pushToTaskCompleteQueue($data){
            \Lactone::debug($this->logMessage($data,'pushToTaskCompleteQueue'));
            return $this->taskCompleteQueue->push($data);
        }

        /**
         * 设置当前任务执行结果
         * @param $result
         */
        protected function taskResults($result){

            $this->pushToTaskCompleteQueue(json_encode(
                [
                    'task_id'   =>$this->task['id'],
                    'results'   =>$result
                ]
            ));
        }

        /**
         * 发送成功之后,对数据进行处理
         */
        abstract public function process(Response $response);

        /**
         * 当前页面的登录机制
         * @return mixed
         */
        abstract  public function Login();

        /**
         * 当前网站是否需要进行登录
         * @return mixed
         */
        abstract public function needLogin();

    }